﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SC
{
    public class MessagePack
    {
        /// <summary>
        /// 消息类型
        /// </summary>
        public MessageType messageType;
        ///// <summary>
        ///// 未序列化的原始消息 
        ///// </summary>
        //public Object messageData;

        public static byte[] headBuf = { 0xAA, 0xAA, 0xAA, 0xAA };//数据头

        public MessagePack()
        {

        }

        /// <summary>
        /// 自定义消息协议
        /// </summary>
        /// <param name="messageType"></param>
        /// <param name="objBuf"></param>
        /// <returns></returns>
        private static byte[] SerilizeBuf(SC.MessageType messageType, ref byte[] objBuf)
        {
            byte[] msgType = new byte[4];//消息类型
            byte[] lengthBuf = new byte[4];//记录数据长度
            msgType = BitConverter.GetBytes((int)messageType);
            lengthBuf = BitConverter.GetBytes(objBuf.Length);
            byte[] sendBuf = new byte[headBuf.Length + msgType.Length + lengthBuf.Length + objBuf.Length];
            System.Buffer.BlockCopy(headBuf, 0, sendBuf, 0, headBuf.Length);
            System.Buffer.BlockCopy(msgType, 0, sendBuf, 4, msgType.Length);
            System.Buffer.BlockCopy(lengthBuf, 0, sendBuf, 8, lengthBuf.Length);
            System.Buffer.BlockCopy(objBuf, 0, sendBuf, 12, objBuf.Length);
            return sendBuf;
        }

        /// <summary>
        /// 编码对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] SerializeObject<T>(SC.MessageType messageType,T obj)
        {
            byte[] objBuf;
            objBuf = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(obj));
            return SerilizeBuf(messageType, ref objBuf);
        }

        /// <summary>
        /// 编码字节流
        /// </summary>
        /// <param name="messageType"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static byte[] SerializeByteStream(SC.MessageType messageType, byte[] stream)
        {
            return SerilizeBuf(messageType, ref stream);
        }

        /// <summary>
        /// 消息数据解析成MessagePack
        /// </summary>
        /// <param name="objBuf"></param>
        /// <returns></returns>
        public static T DeserializeObject<T>(byte[] objBuf)
        {
            return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(objBuf));
        }

        /// <summary>
        /// 比较两个字节数组是否相等
        /// </summary>
        /// <param name="b1">byte数组1</param>
        /// <param name="b2">byte数组2</param>
        /// <returns>是否相等</returns>
        private static bool BytesEquals(byte[] b1, byte[] b2)
        {
            if (b1.Length != b2.Length) return false;
            if (b1 == null || b2 == null) return false;
            for (int i = 0; i < b1.Length; i++)
            {
                if (b1[i] != b2[i])
                {
                    return false;
                } 
            }
            return true;
        }

        /// <summary>
        /// 解析消息 获取消息类型和消息对象字节数组
        /// </summary>
        /// <param name="socketSend"></param>
        /// <param name="msgType"></param>
        /// <param name="objBuf"></param>
        public static void DeserializeBuf(System.Net.Sockets.Socket socketSend, out byte[] msgType, out byte[] objBuf)
        {
            byte[] headBuf = new byte[4];//数据头
            msgType = new byte[4];
            byte[] lengthBuf = new byte[4];//记录数据长度  
            byte[] structBytes = new byte[12];  //4字节数据头 4字节消息类型 4字节数据长度
            int structlength = socketSend.Receive(structBytes, 0, structBytes.Length, System.Net.Sockets.SocketFlags.None);
            System.Buffer.BlockCopy(structBytes, 0, headBuf, 0, headBuf.Length);
            if (BytesEquals(headBuf, SC.MessagePack.headBuf))//数据验证通过
            {
                System.Buffer.BlockCopy(structBytes, 4, msgType, 0, msgType.Length);
                System.Buffer.BlockCopy(structBytes, 8, lengthBuf, 0, lengthBuf.Length);
                int objBufLength = BitConverter.ToInt32(lengthBuf, 0);
                objBuf = new byte[objBufLength];
                
                int recvedCount = 0;
                while (recvedCount < objBufLength)
                {
                    int count = socketSend.Receive(objBuf, recvedCount, objBufLength-recvedCount, System.Net.Sockets.SocketFlags.None);
                    recvedCount += count;
                }
            }
            else
            {
                objBuf = null;
                System.Threading.Thread.Sleep(100);
            }
        }

    } 
}
